import tkinter as tk
from tkinter import filedialog, messagebox, ttk, simpledialog
import os
from datetime import datetime
import tkinter.font as tkFont
from typing import List, Tuple, Optional, Callable
import json
import shutil

class TextEditor:
    """文本编辑器核心功能类"""
    def __init__(self, text_widget: tk.Text):
        self.text_area = text_widget
        
    def cut_text(self) -> Optional[str]:
        """剪切选中的文本"""
        if self.text_area.tag_ranges(tk.SEL):
            selected_text = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
            self.text_area.event_generate("<<Cut>>")
            return selected_text
        return None
        
    def copy_text(self) -> Optional[str]:
        """复制选中的文本"""
        if self.text_area.tag_ranges(tk.SEL):
            selected_text = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
            self.text_area.event_generate("<<Copy>>")
            return selected_text
        return None
        
    def paste_text(self) -> None:
        """粘贴文本"""
        self.text_area.event_generate("<<Paste>>")
        
    def select_all(self) -> None:
        """全选文本"""
        self.text_area.tag_add(tk.SEL, "1.0", tk.END)
        self.text_area.mark_set(tk.INSERT, "1.0")
        self.text_area.see(tk.INSERT)
        
    def get_selected_text(self) -> str:
        """获取选中的文本"""
        try:
            return self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
        except tk.TclError:
            return ""

class ClipboardManager:
    """剪贴板历史管理类"""
    def __init__(self, max_history: int = 10):
        self.history: List[str] = []
        self.max_history = max_history
        
    def add_to_history(self, text: str) -> None:
        """添加文本到剪贴板历史"""
        if text and text not in self.history:
            self.history.insert(0, text)
            if len(self.history) > self.max_history:
                self.history.pop()
                
    def clear_history(self) -> None:
        """清空剪贴板历史"""
        self.history.clear()
        
    def get_history(self) -> List[str]:
        """获取剪贴板历史"""
        return self.history.copy()

class FindReplaceDialog:
    """查找替换对话框类"""
    def __init__(self, parent, text_editor: TextEditor):
        self.parent = parent
        self.text_editor = text_editor
        self.find_dialog = None
        self.replace_dialog = None
        self.last_find_pos = "1.0"  # 记录最后查找位置
        self.find_direction = "forward"  # 查找方向
        
    def open_find_dialog(self) -> None:
        """打开查找对话框"""
        if self.find_dialog and self.find_dialog.winfo_exists():
            self.find_dialog.lift()
            return
            
        self.find_dialog = tk.Toplevel(self.parent)
        self.find_dialog.title("查找")
        self.find_dialog.geometry("350x150")
        self.find_dialog.resizable(False, False)
        self.find_dialog.transient(self.parent)
        self.find_dialog.grab_set()
        
        # 居中对话框
        self.find_dialog.update_idletasks()
        x = (self.parent.winfo_width() - self.find_dialog.winfo_width()) // 2 + self.parent.winfo_x()
        y = (self.parent.winfo_height() - self.find_dialog.winfo_height()) // 2 + self.parent.winfo_y()
        self.find_dialog.geometry(f"+{x}+{y}")
        
        # 控件布局
        tk.Label(self.find_dialog, text="查找内容：").grid(row=0, column=0, padx=10, pady=15, sticky=tk.W)
        self.find_entry = tk.Entry(self.find_dialog, width=30)
        self.find_entry.grid(row=0, column=1, padx=10, pady=15)
        self.find_entry.focus_set()
        
        # 绑定回车键查找
        self.find_entry.bind("<Return>", lambda e: self.find_forward())
        
        # 选项：匹配大小写
        self.match_case_var = tk.BooleanVar()
        tk.Checkbutton(self.find_dialog, text="匹配大小写", variable=self.match_case_var).grid(
            row=1, column=0, columnspan=2, padx=10, sticky=tk.W
        )
        
        # 选项：查找方向
        self.direction_var = tk.StringVar(value="forward")
        direction_frame = tk.Frame(self.find_dialog)
        direction_frame.grid(row=2, column=0, columnspan=2, padx=10, pady=5, sticky=tk.W)
        tk.Radiobutton(direction_frame, text="向前查找", variable=self.direction_var, value="forward").pack(side=tk.LEFT)
        tk.Radiobutton(direction_frame, text="向后查找", variable=self.direction_var, value="backward").pack(side=tk.LEFT)
        
        # 按钮：查找、关闭
        button_frame = tk.Frame(self.find_dialog)
        button_frame.grid(row=3, column=0, columnspan=2, pady=10)
        
        tk.Button(button_frame, text="查找", command=self.find).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="关闭", command=self.close_find_dialog).pack(side=tk.LEFT, padx=10)
        
        # 绑定关闭事件和Esc键
        self.find_dialog.protocol("WM_DELETE_WINDOW", self.close_find_dialog)
        self.find_dialog.bind("<Escape>", lambda e: self.close_find_dialog())
        
    def close_find_dialog(self) -> None:
        """关闭查找对话框"""
        if self.find_dialog:
            self.text_editor.text_area.tag_remove("find_highlight", "1.0", tk.END)
            self.find_dialog.destroy()
            self.find_dialog = None
            
    def find(self) -> None:
        """执行查找"""
        direction = self.direction_var.get()
        if direction == "forward":
            self.find_forward()
        else:
            self.find_backward()
            
    def find_forward(self) -> None:
        """向前查找"""
        self._find_text("forward")
        
    def find_backward(self) -> None:
        """向后查找"""
        self._find_text("backward")
        
    def _find_text(self, direction: str) -> None:
        """查找文本核心逻辑"""
        find_text = self.find_entry.get().strip()
        if not find_text:
            messagebox.showwarning("提示", "请输入查找内容！")
            return
            
        # 清除之前的高亮
        self.text_editor.text_area.tag_remove("find_highlight", "1.0", tk.END)
        
        # 设置查找参数
        case_sensitive = self.match_case_var.get()
        
        # 从当前光标位置开始查找
        start_index = self.text_editor.text_area.index(tk.INSERT)
    
        try:
            pos = None
            if direction == "forward":
                # 向前查找
                pos = self.text_editor.text_area.search(
                    find_text, start_index, tk.END,
                    nocase=not case_sensitive
                )
                if not pos:
                    pos = self.text_editor.text_area.search(
                        find_text, "1.0", tk.END,
                        nocase=not case_sensitive
                    )
            else:
                # 向后查找
                pos = self.text_editor.text_area.search(
                    find_text, start_index, "1.0",
                    backwards=True, nocase=not case_sensitive
                )
                if not pos:
                    pos = self.text_editor.text_area.search(
                        find_text, tk.END, "1.0",
                        backwards=True, nocase=not case_sensitive
                    )
    
            if pos:
                # 计算匹配内容的结束位置并高亮
                end_pos = f"{pos}+{len(find_text)}c"
                self.text_editor.text_area.tag_add("find_highlight", pos, end_pos)
                self.text_editor.text_area.tag_config("find_highlight", background="#FFFF00")
                
                # 根据查找方向分别处理光标位置
                if direction == "forward":
                    self.text_editor.text_area.mark_set(tk.INSERT, end_pos)
                else:
                    self.text_editor.text_area.mark_set(tk.INSERT, pos)
                self.text_editor.text_area.see(tk.INSERT)
                
                # 记录最后查找位置
                self.last_find_pos = end_pos
            else:
                messagebox.showinfo("提示", f"未找到「{find_text}」")
        except Exception as e:
            messagebox.showerror("错误", f"查找失败：{str(e)}")
            
    def open_replace_dialog(self) -> None:
        """打开替换对话框"""
        if self.replace_dialog and self.replace_dialog.winfo_exists():
            self.replace_dialog.lift()
            return
            
        self.replace_dialog = tk.Toplevel(self.parent)
        self.replace_dialog.title("替换")
        self.replace_dialog.geometry("400x200")
        self.replace_dialog.resizable(False, False)
        self.replace_dialog.transient(self.parent)
        self.replace_dialog.grab_set()
        
        # 居中对话框
        self.replace_dialog.update_idletasks()
        x = (self.parent.winfo_width() - self.replace_dialog.winfo_width()) // 2 + self.parent.winfo_x()
        y = (self.parent.winfo_height() - self.replace_dialog.winfo_height()) // 2 + self.parent.winfo_y()
        self.replace_dialog.geometry(f"+{x}+{y}")
        
        # 控件布局
        tk.Label(self.replace_dialog, text="查找内容：").grid(row=0, column=0, padx=10, pady=10, sticky=tk.W)
        self.replace_find_entry = tk.Entry(self.replace_dialog, width=30)
        self.replace_find_entry.grid(row=0, column=1, padx=10, pady=10)
        
        tk.Label(self.replace_dialog, text="替换为：").grid(row=1, column=0, padx=10, pady=5, sticky=tk.W)
        self.replace_with_entry = tk.Entry(self.replace_dialog, width=30)
        self.replace_with_entry.grid(row=1, column=1, padx=10, pady=5)
        
        # 选项：匹配大小写
        self.replace_match_case_var = tk.BooleanVar()
        tk.Checkbutton(self.replace_dialog, text="匹配大小写", variable=self.replace_match_case_var).grid(
            row=2, column=0, columnspan=2, padx=10, sticky=tk.W
        )
        
        # 按钮框架
        button_frame = tk.Frame(self.replace_dialog)
        button_frame.grid(row=3, column=0, columnspan=2, pady=10)
        
        # 按钮：查找下一个、替换、全部替换、关闭
        tk.Button(button_frame, text="查找下一个", command=self.replace_find_next).pack(side=tk.LEFT, padx=5)
        tk.Button(button_frame, text="替换", command=self.replace_single).pack(side=tk.LEFT, padx=5)
        tk.Button(button_frame, text="全部替换", command=self.replace_all).pack(side=tk.LEFT, padx=5)
        tk.Button(button_frame, text="关闭", command=self.close_replace_dialog).pack(side=tk.LEFT, padx=5)
        
        # 绑定关闭事件和Esc键
        self.replace_dialog.protocol("WM_DELETE_WINDOW", self.close_replace_dialog)
        self.replace_dialog.bind("<Escape>", lambda e: self.close_replace_dialog())
        
    def close_replace_dialog(self) -> None:
        """关闭替换对话框"""
        if self.replace_dialog:
            self.text_editor.text_area.tag_remove("find_highlight", "1.0", tk.END)
            self.replace_dialog.destroy()
            self.replace_dialog = None
            
    def replace_find_next(self) -> None:
        """查找下一个"""
        self._find_text("forward")
        
    def replace_single(self) -> None:
        """替换单个匹配项"""
        find_text = self.replace_find_entry.get().strip()
        replace_text = self.replace_with_entry.get()
        
        if not find_text:
            messagebox.showwarning("提示", "请输入查找内容！")
            return
            
        # 获取当前高亮文本的范围
        ranges = self.text_editor.text_area.tag_ranges("find_highlight")
        if ranges:
            # 替换匹配项
            self.text_editor.text_area.delete(ranges[0], ranges[1])
            self.text_editor.text_area.insert(ranges[0], replace_text)
            
            # 清除高亮，查找下一个
            self.text_editor.text_area.tag_remove("find_highlight", "1.0", tk.END)
            self.replace_find_next()
        else:
            self.replace_find_next()
            
    def replace_all(self) -> None:
        """全部替换"""
        find_text = self.replace_find_entry.get().strip()
        replace_text = self.replace_with_entry.get()
        
        if not find_text:
            messagebox.showwarning("提示", "请输入查找内容！")
            return
            
        case_sensitive = self.replace_match_case_var.get()
        count = 0
        start_index = "1.0"
        
        # 禁用文本区域更新以提高性能
        self.text_editor.text_area.config(state=tk.DISABLED)
        
        try:
            while True:
                # 查找匹配项
                pos = self.text_editor.text_area.search(
                    find_text, start_index, tk.END, 
                    nocase=not case_sensitive
                )
                if not pos:
                    break
                    
                # 计算匹配项结束位置
                end_pos = f"{pos}+{len(find_text)}c"
                
                # 替换内容
                self.text_editor.text_area.delete(pos, end_pos)
                self.text_editor.text_area.insert(pos, replace_text)
                
                # 更新下一次查找的起始位置
                start_index = f"{pos}+{len(replace_text)}c"
                count += 1
        finally:
            # 重新启用文本区域
            self.text_editor.text_area.config(state=tk.NORMAL)
        
        messagebox.showinfo("提示", f"共替换 {count} 处匹配项")

class FontManager:
    """字体管理类（优化格式保留逻辑）"""
    def __init__(self, text_widget: tk.Text):
        self.text_area = text_widget
        self.default_font_family = "微软雅黑"
        self.default_font_size = 12
        self.default_font_weight = "normal"
        self.default_font_slant = "roman"
        self.default_underline = False
        self.default_overstrike = False
        self.default_font_color = "#000000"
        
        # 创建默认字体对象
        self.default_font = tkFont.Font(
            family=self.default_font_family,
            size=self.default_font_size,
            weight=self.default_font_weight,
            slant=self.default_font_slant,
            underline=self.default_underline,
            overstrike=self.default_overstrike
        )
        
        # 应用默认字体到文本区域
        self.text_area.configure(font=self.default_font, fg=self.default_font_color)
        
        # 用于存储当前选中文本的格式（默认值为初始配置）
        self.current_font_family = self.default_font_family
        self.current_font_size = self.default_font_size
        self.current_font_weight = self.default_font_weight
        self.current_font_slant = self.default_font_slant
        self.current_underline = self.default_underline
        self.current_overstrike = self.default_overstrike
        self.current_font_color = self.default_font_color
        
    def apply_format_to_selection(self, **kwargs) -> None:
        """将格式应用到选中的文本（优化：保留未修改的现有格式）"""
        if not self.text_area.tag_ranges(tk.SEL):
            return
            
        # 1. 获取选中文本的起始位置和现有标签
        start_pos = self.text_area.index(tk.SEL_FIRST)
        end_pos = self.text_area.index(tk.SEL_LAST)
        existing_tags = self.text_area.tag_names(start_pos)  # 获取选中文本的第一个字符的所有标签
        
        # 2. 提取现有格式（无现有格式则用current_*变量）
        # 初始化格式为当前默认值
        current_format = {
            'family': self.current_font_family,
            'size': self.current_font_size,
            'weight': self.current_font_weight,
            'slant': self.current_font_slant,
            'underline': self.current_underline,
            'overstrike': self.current_overstrike,
            'color': self.current_font_color
        }
        
        # 从现有标签中提取格式（优先使用第一个有格式的标签）
        for tag in existing_tags:
            try:
                # 尝试获取标签的字体配置
                font = self.text_area.tag_cget(tag, "font")
                if font:
                    # 解析字体属性
                    font_obj = tkFont.Font(font=font)
                    current_format.update({
                        'family': font_obj.actual("family"),
                        'size': font_obj.actual("size"),
                        'weight': font_obj.actual("weight"),
                        'slant': font_obj.actual("slant"),
                        'underline': font_obj.actual("underline"),
                        'overstrike': font_obj.actual("overstrike")
                    })
                
                # 尝试获取标签的颜色配置
                color = self.text_area.tag_cget(tag, "foreground")
                if color:
                    current_format['color'] = color
                    
                # 找到第一个有效的格式标签后跳出
                break
            except:
                continue
        
        # 3. 用新格式覆盖需要修改的属性
        current_format.update(kwargs)
        
        # 4. 创建新字体对象
        custom_font = tkFont.Font(
            family=current_format['family'],
            size=current_format['size'],
            weight=current_format['weight'],
            slant=current_format['slant'],
            underline=current_format['underline'],
            overstrike=current_format['overstrike']
        )
        
        # 5. 创建唯一标签并配置样式
        tag_name = f"format_{hash(str(current_format))}_{datetime.now().timestamp()}"
        self.text_area.tag_configure(
            tag_name, 
            font=custom_font,
            foreground=current_format['color']
        )
        
        # 6. 移除选中区域的旧标签并应用新标签
        for tag in existing_tags:
            if tag.startswith("format_"):  # 只移除格式相关标签
                self.text_area.tag_remove(tag, start_pos, end_pos)
        self.text_area.tag_add(tag_name, start_pos, end_pos)
        
        # 7. 更新当前格式记录
        for key, value in current_format.items():
            if key == 'family':
                self.current_font_family = value
            elif key == 'size':
                self.current_font_size = value
            elif key == 'weight':
                self.current_font_weight = value
            elif key == 'slant':
                self.current_font_slant = value
            elif key == 'underline':
                self.current_underline = value
            elif key == 'overstrike':
                self.current_overstrike = value
            elif key == 'color':
                self.current_font_color = value
        
    def set_font_family(self, family: str) -> None:
        """设置字体家族"""
        self.apply_format_to_selection(family=family)
        
    def set_font_size(self, size: int) -> None:
        """设置字体大小"""
        self.apply_format_to_selection(size=size)
        
    def set_bold(self, bold: bool) -> None:
        """设置粗体"""
        weight = "bold" if bold else "normal"
        self.apply_format_to_selection(weight=weight)
        
    def set_italic(self, italic: bool) -> None:
        """设置斜体"""
        slant = "italic" if italic else "roman"
        self.apply_format_to_selection(slant=slant)
        
    def set_underline(self, underline: bool) -> None:
        """设置下划线"""
        self.apply_format_to_selection(underline=underline)
        
    def set_strikethrough(self, strikethrough: bool) -> None:
        """设置删除线"""
        self.apply_format_to_selection(overstrike=strikethrough)
        
    def set_font_color(self, color: str) -> None:
        """设置字体颜色"""
        self.apply_format_to_selection(color=color)
        
    def get_font_info(self) -> str:
        """获取字体信息字符串"""
        weight = "粗体" if self.current_font_weight == "bold" else "常规"
        slant = "斜体" if self.current_font_slant == "italic" else ""
        underline = "下划线" if self.current_underline else ""
        overstrike = "删除线" if self.current_overstrike else ""
        
        styles = [style for style in [weight, slant, underline, overstrike] if style]
        style_text = "、".join(styles) if styles else "常规"
        
        return f"{self.current_font_family} {self.current_font_size}号 {style_text}"

class NoteManager:
    """笔记管理类"""
    def __init__(self, base_path: str = "notes"):
        self.base_path = base_path
        self.trash_path = os.path.join(base_path, "回收站")
        self.metadata_file = os.path.join(base_path, "metadata.json")
        
        # 确保基础目录存在
        self.ensure_directories()
        
        # 加载元数据
        self.metadata = self.load_metadata()
        
    def ensure_directories(self) -> None:
        """确保必要的目录存在"""
        os.makedirs(self.base_path, exist_ok=True)
        os.makedirs(self.trash_path, exist_ok=True)
        
    def load_metadata(self) -> dict:
        """加载元数据"""
        if os.path.exists(self.metadata_file):
            try:
                with open(self.metadata_file, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except:
                return {}
        return {}
        
    def save_metadata(self) -> None:
        """保存元数据"""
        try:
            with open(self.metadata_file, 'w', encoding='utf-8') as f:
                json.dump(self.metadata, f, ensure_ascii=False, indent=2)
        except:
            pass
            
    def set_storage_path(self, new_path: str) -> bool:
        """设置新的存储路径"""
        try:
            # 确保新路径存在
            os.makedirs(new_path, exist_ok=True)
            
            # 如果原路径存在数据，需要迁移
            if os.path.exists(self.base_path) and self.base_path != new_path:
                # 迁移现有数据
                for item in os.listdir(self.base_path):
                    if item != "回收站":  # 回收站单独处理
                        src = os.path.join(self.base_path, item)
                        dst = os.path.join(new_path, item)
                        if os.path.exists(dst):
                            # 如果目标已存在，添加时间戳
                            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                            dst = f"{dst}_{timestamp}"
                        shutil.move(src, dst)
                
                # 迁移回收站
                old_trash = os.path.join(self.base_path, "回收站")
                new_trash = os.path.join(new_path, "回收站")
                if os.path.exists(old_trash):
                    if os.path.exists(new_trash):
                        # 合并回收站内容
                        for item in os.listdir(old_trash):
                            src = os.path.join(old_trash, item)
                            dst = os.path.join(new_trash, item)
                            if os.path.exists(dst):
                                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                                dst = f"{dst}_{timestamp}"
                            shutil.move(src, dst)
                    else:
                        shutil.move(old_trash, new_trash)
            
            # 更新路径
            self.base_path = new_path
            self.trash_path = os.path.join(new_path, "回收站")
            self.metadata_file = os.path.join(new_path, "metadata.json")
            
            # 确保新路径下的必要目录存在
            self.ensure_directories()
            
            # 重新加载元数据
            self.metadata = self.load_metadata()
            
            return True
        except Exception as e:
            print(f"设置存储路径失败: {e}")
            return False
            
    def create_folder(self, folder_path: str) -> bool:
        """创建文件夹"""
        try:
            full_path = os.path.join(self.base_path, folder_path)
            os.makedirs(full_path, exist_ok=True)
            return True
        except:
            return False
            
    def rename_folder(self, old_path: str, new_name: str) -> bool:
        """重命名文件夹"""
        try:
            old_full_path = os.path.join(self.base_path, old_path)
            new_full_path = os.path.join(os.path.dirname(old_full_path), new_name)
            os.rename(old_full_path, new_full_path)
            return True
        except:
            return False
            
    def delete_folder(self, folder_path: str) -> bool:
        """删除文件夹到回收站"""
        try:
            full_path = os.path.join(self.base_path, folder_path)
            trash_full_path = os.path.join(self.trash_path, os.path.basename(folder_path))
            
            # 如果回收站中已存在同名文件夹，添加时间戳
            if os.path.exists(trash_full_path):
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                trash_full_path = f"{trash_full_path}_{timestamp}"
                
            shutil.move(full_path, trash_full_path)
            
            # 记录删除时间
            if 'deleted_items' not in self.metadata:
                self.metadata['deleted_items'] = {}
            self.metadata['deleted_items'][os.path.basename(trash_full_path)] = {
                'original_path': folder_path,
                'delete_time': datetime.now().isoformat(),
                'type': 'folder'
            }
            self.save_metadata()
            return True
        except:
            return False
            
    def create_note(self, folder_path: str, note_name: str, content: str = "") -> bool:
        """创建笔记"""
        try:
            folder_full_path = os.path.join(self.base_path, folder_path)
            note_path = os.path.join(folder_full_path, f"{note_name}.txt")
            
            with open(note_path, 'w', encoding='utf-8') as f:
                f.write(content)
                
            # 记录笔记元数据
            if 'notes' not in self.metadata:
                self.metadata['notes'] = {}
            self.metadata['notes'][f"{folder_path}/{note_name}"] = {
                'create_time': datetime.now().isoformat(),
                'modify_time': datetime.now().isoformat(),
                'tags': []
            }
            self.save_metadata()
            return True
        except:
            return False
            
    def get_folders(self) -> List[str]:
        """获取所有文件夹"""
        folders = []
        for item in os.listdir(self.base_path):
            item_path = os.path.join(self.base_path, item)
            if os.path.isdir(item_path) and item != "回收站":
                folders.append(item)
        return folders
        
    def get_notes(self, folder_path: str) -> List[dict]:
        """获取文件夹中的所有笔记"""
        notes = []
        folder_full_path = os.path.join(self.base_path, folder_path)
        if os.path.exists(folder_full_path):
            for item in os.listdir(folder_full_path):
                if item.endswith('.txt'):
                    note_name = item[:-4]  # 去掉.txt扩展名
                    note_path = os.path.join(folder_full_path, item)
                    stat = os.stat(note_path)
                    
                    # 获取元数据
                    metadata_key = f"{folder_path}/{note_name}"
                    note_metadata = self.metadata.get('notes', {}).get(metadata_key, {})
                    
                    notes.append({
                        'name': note_name,
                        'path': os.path.join(folder_path, item),
                        'create_time': datetime.fromtimestamp(stat.st_ctime),
                        'modify_time': datetime.fromtimestamp(stat.st_mtime),
                        'size': stat.st_size,
                        'tags': note_metadata.get('tags', [])
                    })
        return notes
        
    def sort_notes(self, notes: List[dict], sort_by: str, reverse: bool = False) -> List[dict]:
        """对笔记进行排序"""
        if sort_by == "create_time":
            return sorted(notes, key=lambda x: x['create_time'], reverse=reverse)
        elif sort_by == "modify_time":
            return sorted(notes, key=lambda x: x['modify_time'], reverse=reverse)
        elif sort_by == "title":
            return sorted(notes, key=lambda x: x['name'], reverse=reverse)
        else:  # 自定义排序
            return notes
            
    def move_note(self, note_path: str, target_folder: str) -> bool:
        """移动笔记"""
        try:
            full_note_path = os.path.join(self.base_path, note_path)
            target_full_path = os.path.join(self.base_path, target_folder, os.path.basename(note_path))
            shutil.move(full_note_path, target_full_path)
            return True
        except:
            return False
            
    def delete_note(self, note_path: str) -> bool:
        """删除笔记到回收站"""
        try:
            full_note_path = os.path.join(self.base_path, note_path)
            trash_full_path = os.path.join(self.trash_path, os.path.basename(note_path))
            
            # 如果回收站中已存在同名文件，添加时间戳
            if os.path.exists(trash_full_path):
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                trash_full_path = f"{trash_full_path}_{timestamp}"
                
            shutil.move(full_note_path, trash_full_path)
            
            # 记录删除时间
            if 'deleted_items' not in self.metadata:
                self.metadata['deleted_items'] = {}
            self.metadata['deleted_items'][os.path.basename(trash_full_path)] = {
                'original_path': note_path,
                'delete_time': datetime.now().isoformat(),
                'type': 'note'
            }
            self.save_metadata()
            return True
        except:
            return False
            
    def restore_from_trash(self, item_name: str) -> bool:
        """从回收站恢复"""
        try:
            trash_item_path = os.path.join(self.trash_path, item_name)
            if os.path.exists(trash_item_path):
                deleted_info = self.metadata.get('deleted_items', {}).get(item_name, {})
                original_path = deleted_info.get('original_path', '')
                
                if original_path:
                    original_full_path = os.path.join(self.base_path, original_path)
                    # 确保目标目录存在
                    os.makedirs(os.path.dirname(original_full_path), exist_ok=True)
                    shutil.move(trash_item_path, original_full_path)
                    
                    # 从删除记录中移除
                    if 'deleted_items' in self.metadata:
                        self.metadata['deleted_items'].pop(item_name, None)
                    self.save_metadata()
                    return True
            return False
        except:
            return False
            
    def cleanup_trash(self) -> None:
        """清理回收站中超过30天的项目"""
        try:
            current_time = datetime.now()
            deleted_items = self.metadata.get('deleted_items', {})
            
            items_to_remove = []
            for item_name, info in deleted_items.items():
                delete_time = datetime.fromisoformat(info['delete_time'])
                if (current_time - delete_time).days > 30:
                    trash_item_path = os.path.join(self.trash_path, item_name)
                    if os.path.exists(trash_item_path):
                        if os.path.isdir(trash_item_path):
                            shutil.rmtree(trash_item_path)
                        else:
                            os.remove(trash_item_path)
                    items_to_remove.append(item_name)
            
            # 从元数据中移除过期项目
            for item_name in items_to_remove:
                deleted_items.pop(item_name, None)
            self.save_metadata()
        except:
            pass

class NoteOrganizerPanel:
    """笔记组织管理面板"""
    def __init__(self, parent, note_manager: NoteManager, on_note_selected_callback, on_back_callback):
        self.parent = parent
        self.note_manager = note_manager
        self.on_note_selected = on_note_selected_callback
        self.on_back_callback = on_back_callback
        
        # 创建主框架
        self.frame = tk.Frame(parent)
        self.frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建顶部工具栏
        self.create_toolbar()
        
        # 创建标签页
        self.notebook = ttk.Notebook(self.frame)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 文件夹管理页面
        self.folder_frame = tk.Frame(self.notebook)
        self.notebook.add(self.folder_frame, text="文件夹")
        self.create_folder_ui()
        
        # 笔记列表页面
        self.notes_frame = tk.Frame(self.notebook)
        self.notebook.add(self.notes_frame, text="笔记")
        self.create_notes_ui()
        
        # 回收站页面
        self.trash_frame = tk.Frame(self.notebook)
        self.notebook.add(self.trash_frame, text="回收站")
        self.create_trash_ui()
        
        # 当前选中的文件夹
        self.current_folder = ""
        
    def create_toolbar(self):
        """创建顶部工具栏"""
        toolbar = tk.Frame(self.frame, relief=tk.RAISED, bd=1)
        toolbar.pack(fill=tk.X, padx=5, pady=5)
        
        tk.Button(toolbar, text="返回编辑", command=self.on_back_callback).pack(side=tk.LEFT, padx=5)
        tk.Button(toolbar, text="设置存储位置", command=self.set_storage_location).pack(side=tk.LEFT, padx=5)
        tk.Label(toolbar, text="笔记管理", font=("微软雅黑", 12, "bold")).pack(side=tk.LEFT, padx=10)
        
        # 显示当前存储路径
        self.path_label = tk.Label(toolbar, text=f"存储位置: {self.note_manager.base_path}", 
                                  font=("微软雅黑", 8), fg="gray")
        self.path_label.pack(side=tk.RIGHT, padx=5)
        
    def set_storage_location(self):
        """设置存储位置"""
        new_path = filedialog.askdirectory(
            title="选择笔记存储位置",
            initialdir=self.note_manager.base_path
        )
        
        if new_path and new_path != self.note_manager.base_path:
            if self.note_manager.set_storage_path(new_path):
                messagebox.showinfo("成功", "存储位置已更新")
                # 更新显示的路径
                self.path_label.config(text=f"存储位置: {new_path}")
                # 刷新所有界面
                self.refresh_folders()
                self.refresh_notes()
                self.refresh_trash()
            else:
                messagebox.showerror("错误", "设置存储位置失败")
        
    def create_folder_ui(self):
        """创建文件夹管理界面"""
        # 工具栏
        toolbar = tk.Frame(self.folder_frame)
        toolbar.pack(fill=tk.X, pady=5)
        
        tk.Button(toolbar, text="新建文件夹", command=self.create_new_folder).pack(side=tk.LEFT, padx=2)
        tk.Button(toolbar, text="重命名", command=self.rename_folder).pack(side=tk.LEFT, padx=2)
        tk.Button(toolbar, text="删除", command=self.delete_folder).pack(side=tk.LEFT, padx=2)
        
        # 文件夹树形视图
        self.folder_tree = ttk.Treeview(self.folder_frame)
        self.folder_tree.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 绑定选择事件
        self.folder_tree.bind('<<TreeviewSelect>>', self.on_folder_select)
        
        # 初始化文件夹列表
        self.refresh_folders()
        
    def create_notes_ui(self):
        """创建笔记列表界面"""
        # 工具栏
        toolbar = tk.Frame(self.notes_frame)
        toolbar.pack(fill=tk.X, pady=5)
        
        tk.Button(toolbar, text="新建笔记", command=self.create_new_note).pack(side=tk.LEFT, padx=2)
        tk.Button(toolbar, text="删除", command=self.delete_selected_notes).pack(side=tk.LEFT, padx=2)
        tk.Button(toolbar, text="移动", command=self.move_selected_notes).pack(side=tk.LEFT, padx=2)
        
        # 排序选项
        sort_frame = tk.Frame(self.notes_frame)
        sort_frame.pack(fill=tk.X, pady=2)
        
        tk.Label(sort_frame, text="排序:").pack(side=tk.LEFT)
        self.sort_var = tk.StringVar(value="create_time")
        sort_combo = ttk.Combobox(sort_frame, textvariable=self.sort_var, 
                                 values=["create_time", "modify_time", "title"], 
                                 state="readonly", width=12)
        sort_combo.pack(side=tk.LEFT, padx=5)
        sort_combo.bind('<<ComboboxSelected>>', self.on_sort_change)
        
        self.sort_order_var = tk.BooleanVar(value=False)
        tk.Checkbutton(sort_frame, text="降序", variable=self.sort_order_var, 
                      command=self.on_sort_change).pack(side=tk.LEFT, padx=5)
        
        # 笔记列表
        self.notes_listbox = tk.Listbox(self.notes_frame, selectmode=tk.EXTENDED)
        self.notes_listbox.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 绑定双击事件
        self.notes_listbox.bind('<Double-Button-1>', self.on_note_double_click)
        
    def create_trash_ui(self):
        """创建回收站界面"""
        # 工具栏
        toolbar = tk.Frame(self.trash_frame)
        toolbar.pack(fill=tk.X, pady=5)
        
        tk.Button(toolbar, text="恢复", command=self.restore_selected_items).pack(side=tk.LEFT, padx=2)
        tk.Button(toolbar, text="彻底删除", command=self.permanently_delete_items).pack(side=tk.LEFT, padx=2)
        tk.Button(toolbar, text="清空回收站", command=self.clear_trash).pack(side=tk.LEFT, padx=2)
        
        # 回收站列表
        self.trash_listbox = tk.Listbox(self.trash_frame)
        self.trash_listbox.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 初始化回收站列表
        self.refresh_trash()
        
    def refresh_folders(self):
        """刷新文件夹列表"""
        # 清空现有项目
        for item in self.folder_tree.get_children():
            self.folder_tree.delete(item)
            
        # 添加文件夹
        folders = self.note_manager.get_folders()
        for folder in folders:
            self.folder_tree.insert("", "end", text=folder, values=(folder,))
            
    def refresh_notes(self):
        """刷新笔记列表"""
        self.notes_listbox.delete(0, tk.END)
        
        if self.current_folder:
            notes = self.note_manager.get_notes(self.current_folder)
            # 应用排序
            sort_by = self.sort_var.get()
            reverse = self.sort_order_var.get()
            notes = self.note_manager.sort_notes(notes, sort_by, reverse)
            
            for note in notes:
                display_text = f"{note['name']} ({note['modify_time'].strftime('%Y-%m-%d %H:%M')})"
                self.notes_listbox.insert(tk.END, display_text)
                
    def refresh_trash(self):
        """刷新回收站列表"""
        self.trash_listbox.delete(0, tk.END)
        
        deleted_items = self.note_manager.metadata.get('deleted_items', {})
        for item_name, info in deleted_items.items():
            delete_time = datetime.fromisoformat(info['delete_time'])
            item_type = "文件夹" if info['type'] == 'folder' else "笔记"
            display_text = f"[{item_type}] {item_name} ({delete_time.strftime('%Y-%m-%d %H:%M')})"
            self.trash_listbox.insert(tk.END, display_text)
            
    def create_new_folder(self):
        """创建新文件夹"""
        folder_name = simpledialog.askstring("新建文件夹", "请输入文件夹名称:")
        if folder_name:
            if self.note_manager.create_folder(folder_name):
                self.refresh_folders()
            else:
                messagebox.showerror("错误", "创建文件夹失败")
                
    def rename_folder(self):
        """重命名文件夹"""
        selected = self.folder_tree.selection()
        if selected:
            old_name = self.folder_tree.item(selected[0])['text']
            new_name = simpledialog.askstring("重命名", "请输入新名称:", initialvalue=old_name)
            if new_name and new_name != old_name:
                if self.note_manager.rename_folder(old_name, new_name):
                    self.refresh_folders()
                else:
                    messagebox.showerror("错误", "重命名失败")
        else:
            messagebox.showwarning("警告", "请先选择一个文件夹")
            
    def delete_folder(self):
        """删除文件夹"""
        selected = self.folder_tree.selection()
        if selected:
            folder_name = self.folder_tree.item(selected[0])['text']
            if messagebox.askyesno("确认删除", f"确定要删除文件夹 '{folder_name}' 吗？"):
                if self.note_manager.delete_folder(folder_name):
                    self.refresh_folders()
                    if self.current_folder == folder_name:
                        self.current_folder = ""
                        self.refresh_notes()
                else:
                    messagebox.showerror("错误", "删除文件夹失败")
        else:
            messagebox.showwarning("警告", "请先选择一个文件夹")
            
    def on_folder_select(self, event):
        """文件夹选择事件"""
        selected = self.folder_tree.selection()
        if selected:
            self.current_folder = self.folder_tree.item(selected[0])['text']
            self.refresh_notes()
            
    def create_new_note(self):
        """创建新笔记"""
        if not self.current_folder:
            messagebox.showwarning("警告", "请先选择一个文件夹")
            return
            
        note_name = simpledialog.askstring("新建笔记", "请输入笔记名称:")
        if note_name:
            if self.note_manager.create_note(self.current_folder, note_name):
                self.refresh_notes()
            else:
                messagebox.showerror("错误", "创建笔记失败")
                
    def delete_selected_notes(self):
        """删除选中的笔记"""
        if not self.current_folder:
            messagebox.showwarning("警告", "请先选择一个文件夹")
            return
            
        selected_indices = self.notes_listbox.curselection()
        if selected_indices:
            if messagebox.askyesno("确认删除", f"确定要删除选中的 {len(selected_indices)} 个笔记吗？"):
                # 获取笔记名称
                notes = self.note_manager.get_notes(self.current_folder)
                sort_by = self.sort_var.get()
                reverse = self.sort_order_var.get()
                notes = self.note_manager.sort_notes(notes, sort_by, reverse)
                
                for index in reversed(selected_indices):  # 反向删除避免索引问题
                    note = notes[index]
                    note_path = note['path']
                    if self.note_manager.delete_note(note_path):
                        pass  # 成功删除
                    else:
                        messagebox.showerror("错误", f"删除笔记 '{note['name']}' 失败")
                        
                self.refresh_notes()
        else:
            messagebox.showwarning("警告", "请先选择要删除的笔记")
            
    def move_selected_notes(self):
        """移动选中的笔记"""
        if not self.current_folder:
            messagebox.showwarning("警告", "请先选择一个文件夹")
            return
            
        selected_indices = self.notes_listbox.curselection()
        if selected_indices:
            # 获取目标文件夹
            folders = self.note_manager.get_folders()
            if len(folders) < 2:
                messagebox.showwarning("警告", "至少需要两个文件夹才能移动笔记")
                return
                
            # 创建选择对话框
            move_dialog = tk.Toplevel(self.parent)
            move_dialog.title("移动笔记")
            move_dialog.geometry("300x150")
            move_dialog.transient(self.parent)
            move_dialog.grab_set()
            
            tk.Label(move_dialog, text="选择目标文件夹:").pack(pady=10)
            
            folder_var = tk.StringVar()
            folder_combo = ttk.Combobox(move_dialog, textvariable=folder_var, values=folders, state="readonly")
            folder_combo.pack(pady=5)
            
            def do_move():
                target_folder = folder_var.get()
                if target_folder and target_folder != self.current_folder:
                    # 获取笔记名称
                    notes = self.note_manager.get_notes(self.current_folder)
                    sort_by = self.sort_var.get()
                    reverse = self.sort_order_var.get()
                    notes = self.note_manager.sort_notes(notes, sort_by, reverse)
                    
                    success_count = 0
                    for index in reversed(selected_indices):  # 反向处理避免索引问题
                        note = notes[index]
                        if self.note_manager.move_note(note['path'], target_folder):
                            success_count += 1
                    
                    messagebox.showinfo("提示", f"成功移动 {success_count} 个笔记")
                    self.refresh_notes()
                    move_dialog.destroy()
                else:
                    messagebox.showwarning("警告", "请选择不同的目标文件夹")
            
            button_frame = tk.Frame(move_dialog)
            button_frame.pack(pady=10)
            tk.Button(button_frame, text="确定", command=do_move).pack(side=tk.LEFT, padx=5)
            tk.Button(button_frame, text="取消", command=move_dialog.destroy).pack(side=tk.LEFT, padx=5)
        else:
            messagebox.showwarning("警告", "请先选择要移动的笔记")
            
    def on_sort_change(self, event=None):
        """排序方式改变事件"""
        self.refresh_notes()
        
    def on_note_double_click(self, event):
        """笔记双击事件"""
        selection = self.notes_listbox.curselection()
        if selection:
            index = selection[0]
            notes = self.note_manager.get_notes(self.current_folder)
            sort_by = self.sort_var.get()
            reverse = self.sort_order_var.get()
            notes = self.note_manager.sort_notes(notes, sort_by, reverse)
            
            if index < len(notes):
                note = notes[index]
                # 调用回调函数加载笔记内容
                self.on_note_selected(note)
                
    def restore_selected_items(self):
        """恢复选中的项目"""
        selected_indices = self.trash_listbox.curselection()
        if selected_indices:
            deleted_items = list(self.note_manager.metadata.get('deleted_items', {}).keys())
            for index in selected_indices:
                if index < len(deleted_items):
                    item_name = deleted_items[index]
                    if self.note_manager.restore_from_trash(item_name):
                        pass  # 成功恢复
                    else:
                        messagebox.showerror("错误", f"恢复 '{item_name}' 失败")
                        
            self.refresh_trash()
            self.refresh_folders()
        else:
            messagebox.showwarning("警告", "请先选择要恢复的项目")
            
    def permanently_delete_items(self):
        """彻底删除选中的项目"""
        selected_indices = self.trash_listbox.curselection()
        if selected_indices:
            if messagebox.askyesno("确认删除", "确定要彻底删除选中的项目吗？此操作不可恢复！"):
                deleted_items = list(self.note_manager.metadata.get('deleted_items', {}).keys())
                for index in selected_indices:
                    if index < len(deleted_items):
                        item_name = deleted_items[index]
                        trash_item_path = os.path.join(self.note_manager.trash_path, item_name)
                        try:
                            if os.path.exists(trash_item_path):
                                if os.path.isdir(trash_item_path):
                                    shutil.rmtree(trash_item_path)
                                else:
                                    os.remove(trash_item_path)
                            # 从元数据中移除
                            if 'deleted_items' in self.note_manager.metadata:
                                self.note_manager.metadata['deleted_items'].pop(item_name, None)
                            self.note_manager.save_metadata()
                        except Exception as e:
                            messagebox.showerror("错误", f"删除 '{item_name}' 失败: {str(e)}")
                            
                self.refresh_trash()
        else:
            messagebox.showwarning("警告", "请先选择要删除的项目")
            
    def clear_trash(self):
        """清空回收站"""
        if messagebox.askyesno("确认清空", "确定要清空回收站吗？此操作不可恢复！"):
            try:
                for item in os.listdir(self.note_manager.trash_path):
                    item_path = os.path.join(self.note_manager.trash_path, item)
                    if os.path.isdir(item_path):
                        shutil.rmtree(item_path)
                    else:
                        os.remove(item_path)
                        
                # 清空元数据中的删除记录
                if 'deleted_items' in self.note_manager.metadata:
                    self.note_manager.metadata['deleted_items'] = {}
                self.note_manager.save_metadata()
                
                self.refresh_trash()
            except Exception as e:
                messagebox.showerror("错误", f"清空回收站失败: {str(e)}")

class NotePad:
    """主应用程序类"""
    def __init__(self, root):
        self.root = root
        self.root.title("增强版简易TXT记事本")
        self.root.geometry("800x600")
        
        # 初始化属性
        self.recent_files: List[str] = []
        self.max_recent_files = 5
        self.is_saved = True
        self.current_file = ""
        self.auto_save_id = None
        self.auto_save_interval = 30000  # 30秒自动保存
        self.column_select_mode = False
        
        # 初始化笔记管理器
        self.note_manager = NoteManager()
        
        # 创建主容器
        self.main_container = tk.Frame(root)
        self.main_container.pack(fill=tk.BOTH, expand=True)
        
        # 创建编辑界面
        self.create_editor_interface()
        
        # 创建笔记管理界面（初始隐藏）
        self.create_organizer_interface()
        self.organizer_frame.pack_forget()  # 隐藏管理界面
        
        # 启动自动保存和回收站清理
        self.start_auto_save()
        self.note_manager.cleanup_trash()
        
    def create_editor_interface(self):
        """创建编辑器界面"""
        self.editor_frame = tk.Frame(self.main_container)
        self.editor_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建顶部工具栏
        toolbar = tk.Frame(self.editor_frame, relief=tk.RAISED, bd=1)
        toolbar.pack(fill=tk.X)
        
        tk.Button(toolbar, text="笔记管理", command=self.show_organizer).pack(side=tk.LEFT, padx=5, pady=2)
        
        # 创建文本区域
        self.text_area = tk.Text(
            self.editor_frame, 
            undo=True,
            maxundo=100,
            wrap=tk.WORD,
            selectbackground="#316AC5",
            selectforeground="white"
        )
        self.text_area.pack(fill=tk.BOTH, expand=True)
        self.text_area.focus_set()
        
        # 添加滚动条
        scrollbar = tk.Scrollbar(self.text_area)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.text_area.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.text_area.yview)
        
        # 初始化管理器
        self.text_editor = TextEditor(self.text_area)
        self.clipboard_manager = ClipboardManager()
        self.font_manager = FontManager(self.text_area)
        
        # 创建查找替换对话框
        self.find_replace_dialog = FindReplaceDialog(self.root, self.text_editor)
        
        # 绑定事件
        self.bind_events()
        
        # 创建菜单和状态栏
        self.create_menu()
        self.create_status_bar()
        
    def create_organizer_interface(self):
        """创建笔记管理界面"""
        self.organizer_frame = tk.Frame(self.main_container)
        self.note_organizer = NoteOrganizerPanel(
            self.organizer_frame, 
            self.note_manager, 
            self.load_note_content,
            self.show_editor
        )
        
    def show_organizer(self):
        """显示笔记管理界面"""
        if not self.confirm_unsaved_changes():
            return
        self.editor_frame.pack_forget()
        self.organizer_frame.pack(fill=tk.BOTH, expand=True)
        
    def show_editor(self):
        """显示编辑器界面"""
        self.organizer_frame.pack_forget()
        self.editor_frame.pack(fill=tk.BOTH, expand=True)
        
    def bind_events(self) -> None:
        """绑定事件处理函数"""
        # 文本变化事件
        self.text_area.bind("<KeyRelease>", self.on_text_change)
        
        # 列选模式事件
        self.text_area.bind("<Button-1>", self.on_mouse_click)
        self.text_area.bind("<B1-Motion>", self.on_mouse_drag)
        
        # 快捷键绑定
        self.root.bind("<Control-n>", lambda e: self.new_note())
        self.root.bind("<Control-o>", lambda e: self.open_note())
        self.root.bind("<Control-s>", lambda e: self.save_note())
        self.root.bind("<Control-Shift-S>", lambda e: self.save_note_as())
        self.root.bind("<Control-f>", lambda e: self.find_replace_dialog.open_find_dialog())
        self.root.bind("<Control-h>", lambda e: self.find_replace_dialog.open_replace_dialog())
        self.root.bind("<Control-z>", lambda e: self.undo())
        self.root.bind("<Control-y>", lambda e: self.redo())
        self.root.bind("<Control-a>", lambda e: self.select_all())
        self.root.bind("<Control-x>", lambda e: self.cut())
        self.root.bind("<Control-c>", lambda e: self.copy())
        self.root.bind("<Control-v>", lambda e: self.paste())
        
        # 绑定选择变化事件，更新状态栏
        self.text_area.bind("<<Selection>>", self.on_selection_change)
        
    def on_selection_change(self, event=None) -> None:
        """处理选择变化事件"""
        if self.text_area.tag_ranges(tk.SEL):
            self.update_status("文本已选中")
        
    def create_menu(self) -> None:
        """创建菜单"""
        self.menubar = tk.Menu(self.root)
        
        # 文件菜单
        self.file_menu = tk.Menu(self.menubar, tearoff=0)
        self.file_menu.add_command(label="新建空白笔记", command=self.new_note, accelerator="Ctrl+N")
        self.file_menu.add_command(label="新建待办模板", command=lambda: self.new_template("待办"))
        self.file_menu.add_command(label="新建日记模板", command=lambda: self.new_template("日记"))
        self.file_menu.add_separator()
        self.file_menu.add_command(label="打开笔记", command=self.open_note, accelerator="Ctrl+O")
        
        # 最近文件子菜单
        self.recent_menu = tk.Menu(self.file_menu, tearoff=0)
        self.file_menu.add_cascade(label="最近打开", menu=self.recent_menu)
        self.update_recent_menu()
        
        self.file_menu.add_separator()
        self.file_menu.add_command(label="保存", command=self.save_note, accelerator="Ctrl+S")
        self.file_menu.add_command(label="另存为", command=self.save_note_as, accelerator="Ctrl+Shift+S")
        self.file_menu.add_separator()
        self.file_menu.add_command(label="关闭", command=self.close_note)
        self.file_menu.add_command(label="退出", command=self.quit_app)
        
        self.menubar.add_cascade(label="文件", menu=self.file_menu)
        
        # 编辑菜单
        self.edit_menu = tk.Menu(self.menubar, tearoff=0)
        self.edit_menu.add_command(label="撤销", command=self.undo, accelerator="Ctrl+Z")
        self.edit_menu.add_command(label="重做", command=self.redo, accelerator="Ctrl+Y")
        self.edit_menu.add_separator()
        self.edit_menu.add_command(label="剪切", command=self.cut, accelerator="Ctrl+X")
        self.edit_menu.add_command(label="复制", command=self.copy, accelerator="Ctrl+C")
        self.edit_menu.add_command(label="粘贴", command=self.paste, accelerator="Ctrl+V")
        self.edit_menu.add_separator()
        
        # 剪贴板历史子菜单
        self.clipboard_menu = tk.Menu(self.edit_menu, tearoff=0)
        self.edit_menu.add_cascade(label="剪贴板历史", menu=self.clipboard_menu)
        self.update_clipboard_menu()
        
        self.edit_menu.add_separator()
        self.edit_menu.add_command(label="全选", command=self.select_all, accelerator="Ctrl+A")
        self.edit_menu.add_command(label="查找", command=self.find_replace_dialog.open_find_dialog, accelerator="Ctrl+F")
        self.edit_menu.add_command(label="替换", command=self.find_replace_dialog.open_replace_dialog, accelerator="Ctrl+H")
        
        self.menubar.add_cascade(label="编辑", menu=self.edit_menu)
        
        # 格式菜单
        self.format_menu = tk.Menu(self.menubar, tearoff=0)
        
        # 字体样式子菜单
        self.style_menu = tk.Menu(self.format_menu, tearoff=0)
        self.style_menu.add_command(label="粗体", command=self.toggle_bold)
        self.style_menu.add_command(label="斜体", command=self.toggle_italic)
        self.style_menu.add_command(label="下划线", command=self.toggle_underline)
        self.style_menu.add_command(label="删除线", command=self.toggle_strikethrough)
        self.format_menu.add_cascade(label="字体样式", menu=self.style_menu)
        
        # 字号子菜单
        self.size_menu = tk.Menu(self.format_menu, tearoff=0)
        sizes = [8, 10, 12, 14, 16, 18, 20, 24, 28, 32]
        for size in sizes:
            self.size_menu.add_command(
                label=f"{size}号", 
                command=lambda s=size: self.set_font_size(s)
            )
        self.format_menu.add_cascade(label="字号", menu=self.size_menu)
        
        # 字体颜色子菜单
        self.color_menu = tk.Menu(self.format_menu, tearoff=0)
        colors = [
            ("黑色", "#000000"), ("红色", "#FF0000"), ("蓝色", "#0000FF"), 
            ("绿色", "#008000"), ("黄色", "#FFFF00"), ("紫色", "#800080")
        ]
        for name, code in colors:
            self.color_menu.add_command(
                label=name, 
                command=lambda c=code: self.set_font_color(c)
            )
        self.format_menu.add_cascade(label="字体颜色", menu=self.color_menu)
        
        self.menubar.add_cascade(label="格式", menu=self.format_menu)
        
        # 视图菜单
        self.view_menu = tk.Menu(self.menubar, tearoff=0)
        self.view_menu.add_command(label="切换列选模式", command=self.toggle_column_select)
        self.menubar.add_cascade(label="视图", menu=self.view_menu)
        
        self.root.config(menu=self.menubar)
        
    def create_status_bar(self) -> None:
        """创建状态栏"""
        self.status_var = tk.StringVar()
        self.status_bar = tk.Label(
            self.root, 
            textvariable=self.status_var, 
            bd=1, 
            relief=tk.SUNKEN, 
            anchor=tk.W
        )
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        self.update_status("就绪")
        
    def update_status(self, message: str) -> None:
        """更新状态栏"""
        mode = "列选模式" if self.column_select_mode else "普通模式"
        font_info = self.font_manager.get_font_info()
        color_hex = self.font_manager.current_font_color.upper()
        saved_status = "已保存" if self.is_saved else "未保存"
        
        status_text = f"{message} | {mode} | {font_info} | 颜色: {color_hex} | {saved_status}"
        self.status_var.set(status_text)
        
    def update_recent_menu(self) -> None:
        """更新最近文件菜单"""
        self.recent_menu.delete(0, tk.END)
        
        if not self.recent_files:
            self.recent_menu.add_command(label="无最近文件", state=tk.DISABLED)
            return
            
        for i, file_path in enumerate(self.recent_files):
            filename = os.path.basename(file_path)
            self.recent_menu.add_command(
                label=f"{i+1}. {filename}",
                command=lambda path=file_path: self.open_recent_file(path)
            )
            
        self.recent_menu.add_separator()
        self.recent_menu.add_command(label="清空历史记录", command=self.clear_recent_files)
        
    def update_clipboard_menu(self) -> None:
        """更新剪贴板菜单"""
        self.clipboard_menu.delete(0, tk.END)
        
        history = self.clipboard_manager.get_history()
        if not history:
            self.clipboard_menu.add_command(label="剪贴板为空", state=tk.DISABLED)
            return
            
        for i, text in enumerate(history):
            # 显示前30个字符
            display_text = text[:30] + "..." if len(text) > 30 else text
            self.clipboard_menu.add_command(
                label=f"{i+1}. {display_text}",
                command=lambda t=text: self.paste_from_history(t)
            )
            
        self.clipboard_menu.add_separator()
        self.clipboard_menu.add_command(label="清空剪贴板", command=self.clear_clipboard_history)
        
    def clear_recent_files(self) -> None:
        """清空最近文件列表"""
        self.recent_files.clear()
        self.update_recent_menu()
        
    def clear_clipboard_history(self) -> None:
        """清空剪贴板历史"""
        self.clipboard_manager.clear_history()
        self.update_clipboard_menu()
        
    def add_to_recent_files(self, file_path: str) -> None:
        """添加文件到最近文件列表"""
        if file_path in self.recent_files:
            self.recent_files.remove(file_path)
            
        self.recent_files.insert(0, file_path)
        
        if len(self.recent_files) > self.max_recent_files:
            self.recent_files.pop()
            
        self.update_recent_menu()
        
    def on_text_change(self, event=None) -> None:
        """处理文本变化事件"""
        self.is_saved = False
        self.update_status("编辑中")
        
    def on_mouse_click(self, event) -> None:
        """处理鼠标点击事件"""
        # 检查是否按下Ctrl键（列选模式）
        if event.state & 0x4:  # Ctrl键的状态码
            self.column_select_mode = not self.column_select_mode
            mode_text = "列选模式" if self.column_select_mode else "普通模式"
            self.update_status(f"已切换到{mode_text}")
            
        # 记录起始位置
        self.start_x = event.x
        self.start_y = event.y
        self.start_index = self.text_area.index(f"@{event.x},{event.y}")
        
    def on_mouse_drag(self, event) -> None:
        """处理鼠标拖动事件"""
        if not self.column_select_mode:
            return
            
        # 列选模式下的选择逻辑
        end_index = self.text_area.index(f"@{event.x},{event.y}")
        start_line, start_col = map(int, self.start_index.split('.'))
        end_line, end_col = map(int, end_index.split('.'))
        
        # 清除之前的选择
        self.text_area.tag_remove(tk.SEL, "1.0", tk.END)
        
        # 选择矩形区域
        for line in range(min(start_line, end_line), max(start_line, end_line) + 1):
            col_start = min(start_col, end_col)
            col_end = max(start_col, end_col)
            self.text_area.tag_add(tk.SEL, f"{line}.{col_start}", f"{line}.{col_end}")
            
    def toggle_column_select(self) -> None:
        """切换列选模式"""
        self.column_select_mode = not self.column_select_mode
        mode_text = "列选模式" if self.column_select_mode else "普通模式"
        self.update_status(f"已切换到{mode_text}")
        
    def undo(self) -> None:
        """撤销操作"""
        try:
            self.text_area.edit_undo()
        except tk.TclError:
            pass  # 没有可撤销的操作
            
    def redo(self) -> None:
        """重做操作"""
        try:
            self.text_area.edit_redo()
        except tk.TclError:
            pass  # 没有可重做的操作
            
    def cut(self) -> None:
        """剪切文本"""
        text = self.text_editor.cut_text()
        if text:
            self.clipboard_manager.add_to_history(text)
            self.update_clipboard_menu()
            
    def copy(self) -> None:
        """复制文本"""
        text = self.text_editor.copy_text()
        if text:
            self.clipboard_manager.add_to_history(text)
            self.update_clipboard_menu()
            
    def paste(self) -> None:
        """粘贴文本"""
        self.text_editor.paste_text()
        
    def paste_from_history(self, text: str) -> None:
        """从剪贴板历史粘贴文本"""
        self.text_area.insert(tk.INSERT, text)
        
    def select_all(self) -> None:
        """全选文本"""
        self.text_editor.select_all()
        
    def toggle_bold(self) -> None:
        """切换粗体"""
        is_bold = self.font_manager.current_font_weight == "bold"
        self.font_manager.set_bold(not is_bold)
        self.update_status("字体样式已更改")
        
    def toggle_italic(self) -> None:
        """切换斜体"""
        is_italic = self.font_manager.current_font_slant == "italic"
        self.font_manager.set_italic(not is_italic)
        self.update_status("字体样式已更改")
        
    def toggle_underline(self) -> None:
        """切换下划线"""
        self.font_manager.set_underline(not self.font_manager.current_underline)
        self.update_status("字体样式已更改")
        
    def toggle_strikethrough(self) -> None:
        """切换删除线"""
        self.font_manager.set_strikethrough(not self.font_manager.current_overstrike)
        self.update_status("字体样式已更改")
        
    def set_font_size(self, size: int) -> None:
        """设置字体大小"""
        self.font_manager.set_font_size(size)
        self.update_status("字体大小已更改")
        
    def set_font_color(self, color: str) -> None:
        """设置字体颜色"""
        self.font_manager.set_font_color(color)
        self.update_status("字体颜色已更改")
        
    def new_note(self) -> None:
        """新建笔记"""
        if not self.confirm_unsaved_changes():
            return
            
        self.text_area.delete(1.0, tk.END)
        self.current_file = ""
        self.is_saved = True
        self.update_status("新建空白笔记")
        
    def new_template(self, template_type: str) -> None:
        """新建模板"""
        if not self.confirm_unsaved_changes():
            return
            
        self.text_area.delete(1.0, tk.END)
        
        if template_type == "待办":
            content = "### 待办事项\n\n- [ ] 任务1\n- [ ] 任务2\n- [ ] 任务3\n"
            self.text_area.insert(tk.END, content)
        elif template_type == "日记":
            now = datetime.now()
            date_str = now.strftime("%Y年%m月%d日 %A")
            content = f"# {date_str}\n\n## 今日计划\n\n- [ ] \n\n## 今日总结\n\n"
            self.text_area.insert(tk.END, content)
            
        self.current_file = ""
        self.is_saved = False
        self.update_status(f"新建{template_type}模板")
        
    def open_note(self) -> None:
        """打开笔记"""
        if not self.confirm_unsaved_changes():
            return
            
        file_path = filedialog.askopenfilename(
            title="打开文本文件",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        
        if file_path:
            self.load_file(file_path)
            
    def open_recent_file(self, file_path: str) -> None:
        """打开最近文件"""
        if not self.confirm_unsaved_changes():
            return
            
        if os.path.exists(file_path):
            self.load_file(file_path)
        else:
            messagebox.showerror("错误", f"文件不存在: {file_path}")
            self.recent_files.remove(file_path)
            self.update_recent_menu()
            
    def load_file(self, file_path: str) -> None:
        """加载文件内容"""
        try:
            # 尝试多种编码
            encodings = ['utf-8', 'gbk', 'gb2312', 'latin-1']
            content = None
            
            for encoding in encodings:
                try:
                    with open(file_path, "r", encoding=encoding) as file:
                        content = file.read()
                    break
                except UnicodeDecodeError:
                    continue
            
            if content is None:
                raise UnicodeDecodeError("无法解码文件")
                
            self.text_area.delete(1.0, tk.END)
            self.text_area.insert(1.0, content)
            
            self.current_file = file_path
            self.is_saved = True
            self.add_to_recent_files(file_path)
            self.update_status(f"已打开: {os.path.basename(file_path)}")
            
        except Exception as e:
            messagebox.showerror("错误", f"打开文件失败: {str(e)}")
            
    def load_note_content(self, note_info: dict) -> None:
        """加载笔记内容"""
        if not self.confirm_unsaved_changes():
            return
            
        try:
            note_path = os.path.join(self.note_manager.base_path, note_info['path'])
            with open(note_path, 'r', encoding='utf-8') as f:
                content = f.read()
                
            self.text_area.delete(1.0, tk.END)
            self.text_area.insert(1.0, content)
            
            self.current_file = note_path
            self.is_saved = True
            self.update_status(f"已打开: {note_info['name']}")
            
            # 切换回编辑器界面
            self.show_editor()
            
        except Exception as e:
            messagebox.showerror("错误", f"打开笔记失败: {str(e)}")
            
    def save_note(self) -> None:
        """保存笔记"""
        if self.current_file:
            self.save_to_file(self.current_file)
        else:
            self.save_note_as()
            
    def save_note_as(self) -> None:
        """另存笔记"""
        file_path = filedialog.asksaveasfilename(
            title="保存文本文件",
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        
        if file_path:
            self.save_to_file(file_path)
            self.current_file = file_path
            self.add_to_recent_files(file_path)
            
    def save_to_file(self, file_path: str) -> None:
        """保存内容到文件"""
        try:
            content = self.text_area.get(1.0, tk.END)
            
            with open(file_path, "w", encoding="utf-8") as file:
                file.write(content)
                
            self.is_saved = True
            self.update_status(f"已保存: {os.path.basename(file_path)}")
            
        except Exception as e:
            messagebox.showerror("错误", f"保存文件失败: {str(e)}")
            
    def close_note(self) -> None:
        """关闭笔记"""
        if not self.confirm_unsaved_changes():
            return
            
        self.text_area.delete(1.0, tk.END)
        self.current_file = ""
        self.is_saved = True
        self.update_status("笔记已关闭")
        
    def quit_app(self) -> None:
        """退出应用"""
        if not self.confirm_unsaved_changes():
            return
            
        self.root.quit()
        
    def confirm_unsaved_changes(self) -> bool:
        """确认未保存的更改"""
        if not self.is_saved:
            result = messagebox.askyesnocancel(
                "保存更改",
                "当前笔记有未保存的更改，是否保存？"
            )
            
            if result is None:  # 取消
                return False
            elif result:  # 是
                self.save_note()
                return True
            else:  # 否
                return True
                
        return True
        
    def start_auto_save(self) -> None:
        """启动自动保存"""
        def auto_save():
            if not self.is_saved and self.current_file:
                try:
                    self.save_to_file(self.current_file)
                except Exception as e:
                    # 自动保存失败不提示用户，避免干扰
                    pass
                
            self.auto_save_id = self.root.after(self.auto_save_interval, auto_save)
            
        auto_save()
        
    def stop_auto_save(self) -> None:
        """停止自动保存"""
        if self.auto_save_id:
            self.root.after_cancel(self.auto_save_id)
            self.auto_save_id = None

# 创建主窗口并运行应用
if __name__ == "__main__":
    root = tk.Tk()
    app = NotePad(root)
    root.mainloop()